package cn.xgx.service.impl;

import cn.xgx.exception.MyValidateException;
import cn.xgx.mapper.UserMapper;
import cn.xgx.model.Constant;
import cn.xgx.model.User;
import cn.xgx.model.query.UserQuery;
import cn.xgx.result.ResponseData;
import cn.xgx.service.UserService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

@Service
public class IUserService extends IBaseService<User, UserQuery> implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    protected void beforeGet(Serializable id) {

    }

    @Override
    protected void beforeUpdate(User user) {
        if(user!=null){
            if(userMapper.countByUsernameAndNotId(user.getUsername(),user.getId())>0){
                throw new MyValidateException("账户名重名");
            }
        }
    }

    @Override
    protected void beforeSave(User user) {
        if(user!=null){
            if(userMapper.countByUsername(user.getUsername())>0){
                throw new MyValidateException("账户名重名");
            }
        }
    }

    @Override
    protected void beforeDelete(Serializable[] ids) {

    }

    @Override
    public ResponseData login(String username, String password) {
        if(userMapper.findByUsernameAndPassword(username,password)==1){
            //获取user对象
            User user=userMapper.findByUsername(username);
            //生成token并返回，然后存储到redis里面
            String token=this.getAndSaveTokenInRedis(user.getId());
            HashMap<String, Object> map = new HashMap<>();
            map.put("userinfo",user);
            map.put("Authorization",token);
            return ResponseData.success(map);
        }else{
            return ResponseData.error("密码错误");
        }
    }

    /**
     * 生成redis的key值
     * @param userId
     * @return
     */
    private String getKey(long userId){
        return "user:"+userId;
    }

    private String getAndSaveTokenInRedis(Long userId) {
        // 将token存储到redis中
        //将userId给token携带
        HashMap<String, Object> map = new HashMap<>();
        map.put("userId", userId);
        // 生成token
        String token = Jwts.builder()
                .signWith(SignatureAlgorithm.HS256, Constant.tokenKey)
                .setClaims(map)
                .setIssuedAt(new Date())
                .compact();
        //存储到redis中
        ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
        // 保存120分钟
        operations.set(this.getKey(userId), token,120, TimeUnit.MINUTES);
        return token;
    }


    @Override
    public ResponseData removeToken(String token) {
        if(StringUtils.hasLength(token)){
            Claims claims=null;
            try{
                //如果token在解析的时候出问题，说明token值非法
                claims = Jwts.parser()
                        .setSigningKey(Constant.tokenKey)
                        .parseClaimsJws(token)
                        .getBody();
            }catch (Exception e){
                return ResponseData.unAuthorizedError();
            }
            if(claims!=null){
                Integer userId = (Integer)claims.get("userId");
                //生成key
                String key=this.getKey(userId);
                //从redis中移除
                if(redisTemplate.hasKey(key)){ // 如果key在redis中存在
                    //获取redis的操作对象
                    ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
                    // 获取redis中存储的token
                    String tokenOrigin=(String)operations.get(key);
                    if(token.equals(tokenOrigin)){//如果token一致
                        //则移除token
                        redisTemplate.delete(key);
                    }else{//如果token不一致，说明token值过期
                        return ResponseData.unAuthorizedError();
                    }
                }
            }
        }
        return ResponseData.success(null);
    }

    @Override
    public boolean validateAndRereshToken(String token) {
        boolean result=false;//默认失败，级没有登录凭证
        if(StringUtils.hasLength(token)){
            Claims claims=null;
            try{
                //如果token在解析的时候出问题，说明token值非法
                claims = Jwts.parser()
                        .setSigningKey(Constant.tokenKey)
                        .parseClaimsJws(token)
                        .getBody();
            }catch (Exception e){
                return false;
            }
            //如果没有验证成功，底下代码也不会执行
            if(claims!=null){
                Integer userId = (Integer)claims.get("userId");
                //生成key
                String key=this.getKey(userId);
                if(redisTemplate.hasKey(key)){ // 如果key在redis中存在
                    //获取redis的操作对象
                    ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
                    // 获取redis中存储的token
                    String tokenOrigin=(String)operations.get(key);
                    if(token.equals(tokenOrigin)){//如果token一致
                        //则延长时间
                        redisTemplate.expire(key,120, TimeUnit.MINUTES);
                        result=true;//表示验证成功
                    }
                }
            }
        }
        return result;
    }
}
